package com.asm.shiroweb.config;

import com.asm.shiroweb.cache.MyRedisCacheManager;
import com.asm.shiroweb.cache.MyRedisSession;
import com.asm.shiroweb.common.constant.CacheExpireContant;
import com.asm.shiroweb.common.util.EncryptionPassword;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.HashMap;

/*
基础框架搭建 ： shiro配置三板斧
 */
//@Configuration      *************** 这里注释 防止重复创建Bean报错 ***************
public class ShiroConfig_备份 {
    /*
    #################################################################################
    ########################                                  #######################
    ########################       1. Realm 代表系统资源        #######################
    ########################                                  #######################
    #################################################################################
     */
    @Bean
    public AuthorizingRealm myRealm()
    {
         MyRealm myRealm = new MyRealm();

        return myRealm;
    }
    @Bean
    public AuthenticatingRealm mobileRealm()
    {
        MobileRealm mobileRealm = new MobileRealm();

        return mobileRealm;
    }



    /*
    #################################################################################
    ########################                                  #######################
    ########################       2. SecurityManager        #######################
    ########################                                  #######################
    #################################################################################
     * AuthorizingRealm extends AuthenticatingRealm
     */
    /*
    ***********************************************************************************
    /                                                                                 /
    / 6. redis 保存  Session会话管理器    【 此时 登录的rememberMe要打开 存状态】           /
    /    1. 每请求一次 redis里session有效期更新                                          /
    /                                                                                 /
    -----------------------------------------------------------------------------------
    */
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager() {

        // 6.1 【自定义的RedisSession】 并设置过期时间
        MyRedisSession redisSession = new MyRedisSession();
        redisSession.setExpireTime(CacheExpireContant.REDIS_SESSION_EXPIRE.getSeconds());

        // 6.2 Cookie对象
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("shiro-session");// session对应的cookie有效期不设置，由session管理时间

        // 6.2 创建Session会话管理器
        final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSession);
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(simpleCookie);
        sessionManager.setGlobalSessionTimeout(CacheExpireContant.REDIS_SESSION_EXPIRE.getSeconds()*1000);// 秒 -> 毫秒

        /*
        -----------------------------------------------
        /                                             |
        /  关闭 sessionId 重写地址                      |
        /  很重要：这样没有权限时                        |
        /         将不会在地址后面 + ';JSESSIONID=...'  |
        /                                             |
        +++++++++++++++++++++++++++++++++++++++++++++++
        */
        sessionManager.setSessionIdUrlRewritingEnabled(false);

        return sessionManager;
    }

    /*
    ******************************************************************************************
    /                                                                                        /
    / 7. redis 管理 CacheManager  【前提：用包：<artifactId>shiro-redis</artifactId> 】         /
    /                                                                                        /
    ------------------------------------------------------------------------------------------
    */
    @Bean
    public RedisCacheManager getRedisCacheManager(){
        // 1. 创建jar包里的 redis管理
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost:6379");
        redisManager.setPassword("hb@12345");
        redisManager.setDatabase(0);
        // 2. 创建 jar包里的 redis缓存管理器
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager);
        redisCacheManager.setKeyPrefix("jarRedisCacheManager-");
        redisCacheManager.setExpire(CacheExpireContant.REDIS_CACHE_MANAGER_EXPIRE.getSeconds());

        return redisCacheManager;
    }
    @Bean
    public DefaultWebSecurityManager mySecurityManager(
            AuthorizingRealm myRealm,
            AuthenticatingRealm mobileRealm,
            DefaultWebSessionManager defaultWebSessionManager,
            RedisCacheManager redisCacheManager
    ){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 1. 设置Realm的 密码加密方式
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(EncryptionPassword.ALGORITHM);
        matcher.setHashIterations(EncryptionPassword.ITERATIONS);
        /*
        --------------------------------------
        /                                    /
        /  salt在 自定义Realm里的 认证方法里加  /
        /                                    /
        ======================================
         */
        myRealm.setCredentialsMatcher(matcher);
        mobileRealm.setCredentialsMatcher(matcher);

        // 2. 设置缓存 【作用：无需每次验证权限角色 都 进入 授权方法 doGetAuthorizationInfo()】
//>>>>>>>>>>>>>>>>>>>>>>>

//        ********* 方式一 *********
//        CacheManager cacheManager = new MemoryConstrainedCacheManager();
//        securityManager.setCacheManager(cacheManager);
//=======================

//        ********* 方式二 *********
        // 自定义的 RedisCacheManager管理 shiro缓存
        MyRedisCacheManager cacheManager = new MyRedisCacheManager();// 这个只能new一次

        myRealm.setCacheManager(cacheManager);
        myRealm.setCachingEnabled(true);
        myRealm.setAuthorizationCachingEnabled(true); // 开启 授权管理器 缓存
        myRealm.setAuthorizationCacheName("authorizationCacheMyRealm");// 设置 授权器 名称(默认realm名+authorization)
        myRealm.setAuthenticationCachingEnabled(true);// 开启 认证管理器 缓存
        myRealm.setAuthenticationCacheName("authenticationCacheMyRealm");

        mobileRealm.setCacheManager(cacheManager);
        mobileRealm.setCachingEnabled(true);
        mobileRealm.setAuthenticationCachingEnabled(true);// 开启 认证管理器 缓存
        mobileRealm.setAuthenticationCacheName("authenticationCacheMobile");

//<<<<<<<<<<<<<<<<<<<<<<<

        // 3. 设置自定义的 Realm
        securityManager.setRealms(Arrays.asList(myRealm,mobileRealm));

        // 4. 设置自定义认证策略 【系统默认---AtLeastOneSuccessfulStrategy； 这里只是测试】
        /*final ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        modularRealmAuthenticator.setRealms(Arrays.asList(myRealm,mobileRealm));
        securityManager.setAuthenticator(modularRealmAuthenticator);*/

        // 5. 设置记住我时长
        final CookieRememberMeManager cookieRemember = new CookieRememberMeManager();
        Cookie cookie = new SimpleCookie("cookie-remember");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(CacheExpireContant.SHIRO_REMEMBER_EXPIRE.getSeconds());
        cookieRemember.setCookie(cookie);

        securityManager.setRememberMeManager(cookieRemember);

        // 6. session会话设置
        securityManager.setSessionManager(defaultWebSessionManager);

        return securityManager;
    }




    /*
    #################################################################################
    ###############                                                   ###############
    ###############       3. ShiroFilterFactoryBean 请求过滤器         ###############
    ###############                                                   ###############
    #################################################################################
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager mySecurityManager){
        
        final ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(mySecurityManager);

        /*
        ######################################################################################
        #########                                                                      #######
        #########           设置过滤器()  【越详细规则 建议往上放】                         #######
        #########           /mobile/*  优先于    /mobile/query                          #######
        #########           /mobile/** 优先级最低                                       #######
        #########           anon       可匿名访问                                       #######
        #########           authc      登录的 首次 session有效期内访问(不管是否有角色)      #######
        #########           user       身份验证/记住我 都可以访问                         #######
        #########                                                                      #######
        #########                                                                      #######
        ######################################################################################

        配置路径过滤器    【shiro枚举类：DefaultFilter】 详情看 [过滤器.md]
         */
        final HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/common/**", "anon");  // anon  可匿名访问

//        filterMap.put("/mobile/**", "authc,perms[mobile]"); // perms 资源权限 才可以访问
//        filterMap.put("/salary/**", "authc"); // authc 登录才可以访问

        filterMap.put("/common/getCurrentUser", "authc");
        filterMap.put("/common/logout",        "logout"); // 登出

        filterMap.put("/salary/user",            "user");


        factoryBean.setFilterChainDefinitionMap(filterMap);

//        factoryBean.setUnauthorizedUrl("/common/unauthorized"); // 设置未经授权页面 【引导没权限进入此页面】
        factoryBean.setLoginUrl("/common/needLogin"); // 设置登录页面 【是静态页面】【引导未登录(和退出)跳转此页面】
//        factoryBean.setSuccessUrl();          // 前台设置跳转 这里不设置

        return factoryBean;
    }


}
